// (c) Copyright 2013 Mike Riedel.
// This source is subject to the Microsoft Public License (Ms-PL).
// All other rights reserved.

using System;
using System.Linq;

namespace FreshMeat.ErrorHandlingBlock
{
   /// <summary>
   /// Provides boilerplate functionality for an error detector.
   /// </summary>
   public abstract class ErrorDetector : IErrorDetector
   {
      /// <summary>
      /// Determines whether the error fits this category.
      /// </summary>
      /// <param name="error">The error.</param>
      /// <returns>True if it fits this category.</returns>
      public bool IsRelevant(Exception error)
      {
         return Check(error) != null;
      }

      /// <summary>
      /// Diagnoses the error.
      /// </summary>
      /// <param name="error">The error.</param>
      /// <returns>The passed-in instance if sufficient or a new exception that
      /// better describes or classifies the error.</returns>
      public Exception Diagnose(Exception error)
      {
         if (error is AggregateException)
            return DigIn(error as AggregateException);

         return Check(error);
      }

      /// <summary>
      /// When implemented in a derived class, checks the error and either returns it unchanged,
      /// returns a substitute error.
      /// </summary>
      /// <param name="error"></param>
      /// <returns></returns>
      protected abstract Exception Check(Exception error);

      Exception DigIn(AggregateException aggregateException)
      {
         var mapped = aggregateException.InnerExceptions.Select(Diagnose).ToList();
         if (mapped.Count == 1)
            return mapped.First();
         return new AggregateException(mapped);
      }
   }
}